/**
 * A Spell. You don't actually want to cast spells yourself, because your Minions should do that for you.
 * You should focus on world domination instead.
 * 
 * @author back2dos
 */
class Spell {
	//{ region fields
		///the update function
		public var update:Function;
		///unique id
		private var id:Number;
		///the end handler
		private var onEnd:Function;
		///the start time
		private var t0:Number;
		///the duration
		private var duration:Number;		
	//} endregion
	/**
	 * Cast a Spell
	 * @param	duration the duration of the Spell
	 * @param	updater the Function to be carried out (the actual magic as a function of progress)
	 * @param	onEnd a final callback to invoke when this spell is completed
	 */
	public function Spell(duration:Number, updater:Function, onEnd:Function) {
		this.id = counter++;
		Spell.init();
		this.duration = duration;
		this.update = updater;
		this.onEnd = onEnd;
		this.t0 = getTimer();		
		spells[this.id] = this;
	}
	/**
	 * Cancels this spell (if active)
	 * @param	render if true and the spell is active, the current spell will be instantly finished
	 * @param	callback if true and the spell is active, the callback of this spell will be invoked
	 */
	public function cancel(render:Boolean, callback:Boolean):Void {
		if (delete spells[this.id]) {
			if (render) 
				this.update(1);
			if (callback)
				this.onEnd();			
		}
	}
	/**
	 * Progresses an active spell in time
	 * @param	t
	 */
	private function progress(t:Number):Void {
		var pos:Number = (t - t0) / duration;
		if (pos > 1) 
			this.cancel(true, true);
		else 
			update(pos);		
	}
	///A counter to produce unique spell ids
	static private var counter:Number = 0;
	///A map of all active spells
	static private var spells:/*Spell*/Array;
	///In the beginning, there was nothing. But then the overlord came along and initialized all magic.
	static private function init():Void {
		var spells:/*Spell*/Array = Spell.spells = []; 
		_root.createEmptyMovieClip('spells', _root.getNextHighestDepth()).onEnterFrame = function ():Void {
			var t:Number = getTimer();
			/**
			 * this loop may be a horrible idea, because adding/removing keys 
			 * to an object iterated upon is quite non-deterministic to say the least
			 */
			for (var name:String in spells)
				spells[name].progress(t);
		}
		Spell.init = null;
	}
}